package com.eckey.lab.inteceptor;

import com.alibaba.fastjson.JSON;
import com.eckey.lab.entity.Log;
import com.eckey.lab.service.LogService;
import com.eckey.lab.thread.SaveSystemLogThread;
import com.eckey.lab.utils.IpInfoUtil;
import com.eckey.lab.utils.RequestWrapper;
import com.eckey.lab.utils.SpringHelper;
import com.eckey.lab.utils.ThreadPoolUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class LogInterceptor implements HandlerInterceptor {

    private static final String SYSTEM_LOG = "SYSTEM_LOG";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
        //线程绑定变量（该数据只有当前请求的线程可见）
        Date beginTime = new Date();
        Log systemLog = new Log();
        systemLog.setRequestUrl(request.getRequestURI());
        systemLog.setStartTime(beginTime);
        systemLog.setIp(IpInfoUtil.getIpAddr(request));

        //请求方式
        systemLog.setRequestType(request.getMethod());
        HashMap<String, Object> params = new HashMap<>();
        Map<String, String[]> parameterMap = request.getParameterMap();
        params.put("head", parameterMap);
        RequestWrapper requestWrapper;
        if (request instanceof RequestWrapper) {
            // 签名处理过程 start....
            requestWrapper = (RequestWrapper) request;
            String requestParam = getBodyString(requestWrapper);
            params.put("body", requestParam);
        }

        //设置请求参数
        systemLog.setRequestParam(JSON.toJSONString(params));
        //其他属性
        systemLog.setCreateBy("system");
        systemLog.setDelFlag(0);
        systemLog.setStartTime(beginTime);
        //日志标题
        systemLog.setName(request.getHeader("description"));
        //日志类型
        systemLog.setLogType(Integer.valueOf(request.getHeader("type")));
        request.setAttribute(SYSTEM_LOG, systemLog);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) throws Exception {
        Date endTime = new Date();
        Log systemLog = (Log) request.getAttribute(SYSTEM_LOG);
        systemLog.setEndTime(endTime);
        long costTime = endTime.getTime() - systemLog.getStartTime().getTime();
        systemLog.setCostTime((int) costTime);
        systemLog.setCreateTime(new Date());
        LogService logService = (LogService) SpringHelper.getBean("logService");
        ThreadPoolUtil.getPool().execute(new SaveSystemLogThread(systemLog, logService));
    }

    //通过request.getReader()的方式来获取body
    private String getBodyString(HttpServletRequest request) throws IOException {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line = "";
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString().trim();
    }
}
